﻿using DTO;
using ElasticSearch.Core;
using Nest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ElasticSearchAccess
{
    public abstract class AccessCore<T, Q>
        where T : Entity.BaseEntity
        where Q : PageQuery
    {
        private string IndexName
        {
            get
            {
                return typeof(T).Name.ToLower();
            }
        }

        private string TypeName
        {
            get
            {
                return typeof(T).Name.ToLower();
            }
        }

        /// <summary>
        /// 排序字段
        /// </summary>
        protected virtual string OrderByName
        {
            get
            {
                return "creationTime";
            }
        }

        private Indices Indices
        {
            get { return Indices.Parse(IndexName); }
        }

        private Types Types
        {
            get { return Types.Parse(TypeName); }
        }

        protected ElasticClient Client
        {
            get
            {
                return SearchProvider.ElasticClient<T>();
            }
        }

        protected virtual IIndexResponse Add(T entity)
        {
            var res = SearchProvider.Insert(entity);
            return res;
        }

        protected virtual List<T> PageQuery(Q query)
        {
            if (query == null) return new List<T>();

            var count = Client.Count<T>(CreatCountRequest(query)).Count;
            query.Pagination.DataCount = count;
            var searchResult = Client.Search<T>(CreatSearchRequest(query));
            var entities = searchResult.Documents.ToList();
            return entities;
        }

        protected virtual Func<CountDescriptor<T>, ICountRequest> CreatCountRequest(Q query)
        {
            Func<CountDescriptor<T>, ICountRequest> result;
            var querys = CreatQueryContainer(query);
            Func<QueryContainerDescriptor<T>, QueryContainer> condition = q =>
                    q.Bool(b => b.Must(querys.ToArray()));

            result = o => o.Query(condition);
            return result;
        }

        protected virtual Func<SearchDescriptor<T>, ISearchRequest> CreatSearchRequest(Q query)
        {
            Func<SearchDescriptor<T>, ISearchRequest> result;
            var querys = CreatQueryContainer(query);
            Func<QueryContainerDescriptor<T>, QueryContainer> condition = q =>
                    q.Bool(b => b.Must(querys.ToArray()));
            if (query.Pagination.IsPaging)
            {
                result = o => o
                .Query(condition)
                .Skip(query.Pagination.Skip).Take(query.Pagination.Take)
                .Sort(ss => ss.Descending(OrderByName));
            }
            else
            {
                result = o => o.Query(condition).Sort(ss => ss.Descending(OrderByName));
            }
            return result;
        }

        protected virtual List<Func<QueryContainerDescriptor<T>, QueryContainer>> CreatQueryContainer(Q Query)
        {
            return new List<Func<QueryContainerDescriptor<T>, QueryContainer>>();
        }
    }
}